package com.test.lucene.helper;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

/**
 * The command line parameters shared by {@link SearchParameters} and
 * {@link WriteParameters}.
 * 
 * @author Patrick Kimber
 * 
 */
public abstract class SharedParameters {

    /** Command line parameters. */
    protected static final String OPTION_SLEEP = "sleep";

    /** Command line parameters. */
    protected static final String OPTION_HELP = "help";

    /** Command line parameters. */
    protected static final String OPTION_MINUTES = "minutes";

    /** Command line parameters. */
    protected static final String OPTION_REPOSITORY = "repository";

    /** The name of the main class. */
    private String className;

    /** The command line. */
    private CommandLine commandLine;

    /**
     * Constructor.
     * 
     * @param name
     *            The name of the main class.
     * @param params
     *            Command line parameters.
     */
    public SharedParameters(final String name, final String[] params) {
        try {
            setClassName(name);
            CommandLineParser parser = new GnuParser();
            setCommandLine(parser.parse(getOptions(), params));
            if (isHelp()) {
                displayHelp();
            } else if (!isValid()) {
                System.err.println("Invalid Parameters...");
                displayHelp();
            }
        } catch (ParseException e) {
            System.err.println("Parsing failed.  Reason: " + e.getMessage());
            displayHelp();
        }
    }

    /**
     * @param value
     *            Set the commandLine.
     */
    protected final void setCommandLine(final CommandLine value) {
        this.commandLine = value;
    }

    /**
     * @param value
     *            Set the className.
     */
    protected final void setClassName(final String value) {
        this.className = value;
    }

    /** @return the className. */
    protected final String getClassName() {
        return className;
    }

    /** @return the commandLine. */
    protected final CommandLine getCommandLine() {
        return commandLine;
    }

    /**
     * Get the options for the application.
     * 
     * @return The command line options.
     */
    protected abstract Options getOptions();

    /**
     * Has the user specified the correct command line parameters?
     * 
     * @return <code>true</code> If the user has displayed the correct command
     *         line parameters.
     */
    public abstract boolean isValid();

    /**
     * Get the number of minutes we should run the test for....
     * 
     * @return The number of minutes.
     */
    public final int getMinutes() {
        return Integer
                .parseInt(getCommandLine().getOptionValue(OPTION_MINUTES));
    }

    /**
     * Get the location of the Lucene repository folder.
     * 
     * @return The location of the repository folder.
     */
    public final String getRepositoryFolder() {
        return getCommandLine().getOptionValue(OPTION_REPOSITORY);
    }

    /**
     * Get the number of milliseconds to sleep between each search query.
     * 
     * @return The number of milliseconds.
     */
    public final long getSleep() {
        long result = Constants.DEFAULT_SLEEP;
        if (getCommandLine().hasOption(OPTION_SLEEP)) {
            result = Long.parseLong(getCommandLine().getOptionValue(
                    OPTION_SLEEP));
        }
        return result;
    }

    /**
     * Does the user want to display help text?
     * 
     * @return <code>true</code> If the user wants to display help.
     */
    protected final boolean isHelp() {
        return getCommandLine().hasOption(OPTION_HELP);

    }

    /**
     * Display help.
     */
    protected final void displayHelp() {
        new HelpFormatter().printHelp(getClassName(), getOptions());
    }

    /**
     * Get the options which are used by both applications.
     * 
     * @return The command line options.
     */
    protected final Options getSharedOptions() {
        Option delay = OptionBuilder.withArgName(OPTION_SLEEP).hasArg()
                .withDescription(
                        "number of milliseconds to sleep between each search query."
                                + "(will default to " + Constants.DEFAULT_SLEEP
                                + " milliseconds).").create(OPTION_SLEEP);
        Option help = new Option(OPTION_HELP, "print this message");
        Option minutes = OptionBuilder
                .withArgName(OPTION_MINUTES)
                .hasArg()
                .withDescription(
                        "run the search application for this number of minutes.")
                .create(OPTION_MINUTES);
        Option repository = OptionBuilder.withArgName(OPTION_REPOSITORY)
                .hasArg().withDescription("location of Lucene repository.")
                .create(OPTION_REPOSITORY);
        Options options = new Options();
        options.addOption(delay);
        options.addOption(help);
        options.addOption(minutes);
        options.addOption(repository);
        return options;
    }
}
